import * as crypto from 'crypto';

/**
 * 通用工具方法类
 */
class CommonUtil {
  /**
   * 将parentObj设置为subObj的原型对象
   *
   * @param subObj  子对象
   * @param parentObj 父对象
   * @return {any} 合并结果
   */
  public extend(subObj: any, parentObj: any): any {
    let res;
    const type = this.toType(subObj);

    if (type === 'Object') {
      res = Object.create(parentObj || {});
    } else if (type === 'Array') {
      res = [].concat(parentObj || []);
    }

    if (res) {
      for (const index in subObj) {
        if (Object.hasOwnProperty.call(subObj, index)) {
          res[index] = this.extend(subObj[index], res[index]);
        }
      }
      return res;
    } else {
      return subObj;
    }
  }

  /**
   * 获取变量的类型
   *
   * 与typeof关键字的区别：
   * 当操作数是数字、字符串、布尔值、undefined或者Symbol时，两种方式的效果相同
   *
   * 当操作数是null时，两种方式的效果不同:
   *    toType(null) === "Null"; // true
   *    typeof null === "object"; // true
   *
   * 当操作数是数组时，两种方式的效果不同
   *    toType([]) === "Array"; // true
   *    typeof [] === "object"; // true
   *
   * 当操作数是函数时，两种方式的效果不同
   *    toType(function () {}) === "Function"; // true
   *    typeof function () {} === "function"; // true
   *
   * 当操作数是日期时，两种方式的效果不同
   *    toType(new Date()) === "Date"; // true
   *    typeof new Date() === "object"; // true
   *
   * 当操作数是正则表达式时，两种方式的效果不同
   *    toType(/regex/) === "RegExp"; // true
   *    typeof /regex/ === "object"; // true
   *
   * @param value
   * @return {string} 类型字符串
   */
  public toType(value: any): string {
    return value === null ? 'Null' : toString.call(value).slice(8, -1);
  }

  /**
   * 生成任意长度的字符串
   *
   * @param {number} bytesLen 长度
   * @return {string}
   */
  public genRandomString(bytesLen: number): string {
    return crypto.randomBytes(bytesLen).toString('hex').toUpperCase();
  }

  /**
   * 计算对象的hash值
   *
   * @param {never} obj
   * @return {string}
   */
  public hash(obj: object | undefined): string | undefined {
    if (obj === undefined) {
      return undefined;
    }
    return crypto.createHash('sha256').update(JSON.stringify(obj)).digest('hex');
  }

  /**
   * 删除ANSI码字符
   *
   * @param {string} str
   * @return {string}
   */
  public removeANSI(str: string): string {
    if (!str) {
      return '';
    }

    // 使用正则表达式匹配ANSI转义序列
    // eslint-disable-next-line no-control-regex
    const regex = /\x1b[[0-9;]*m/g;

    // 使用空字符串替换匹配到的结果
    return str.replace(regex, '');
  }
}

export const commonUtil = new CommonUtil();
